﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace AMM.CustomWinControls {
    public partial class DataGridViewEx : DataGridView {

        public DataGridViewEx() {
            this.AlternatingRowsDefaultCellStyle.BackColor = Color.LightGray;
        }

        public virtual List<T> GetSelectedRows<T>() {
            this.EndEdit();
            if (this.IsShowCheckboxForSelected) {
                return this.Rows
                           .Cast<DataGridViewRow>()
                           .Where(x => Convert.ToBoolean(x.Cells[0].Value) == true)
                           .Select(x => (T)x.DataBoundItem)
                           .ToList();
            }
            else {
                return null;
            }
        }

        protected override void OnCellFormatting(DataGridViewCellFormattingEventArgs e) {
            base.OnCellFormatting(e);
            if ((this.Rows[e.RowIndex].DataBoundItem != null) && (this.Columns[e.ColumnIndex].DataPropertyName.Contains("."))) {
                e.Value = BindProperty(this.Rows[e.RowIndex].DataBoundItem, this.Columns[e.ColumnIndex].DataPropertyName);
            }
        }

        protected override void OnDataSourceChanged(EventArgs e) {
            base.OnDataSourceChanged(e);
            if (this.DataGridViewModelType == null) { return; }
            int adjustWith = 40;
            // Will set header text by reflecting DescriptionAttribute from ViewModel
            object[] attributes;
            DescriptionAttribute descriptionAttribute;
            foreach (PropertyInfo pi in this.DataGridViewModelType.GetProperties()) {
                attributes = pi.GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (attributes.Length == 0) {
                    if (this.Columns.Contains(pi.Name)) {
                        this.Columns[pi.Name].Visible = false;
                    }
                    continue;
                }
                descriptionAttribute = (DescriptionAttribute)attributes[0];
                if (this.Columns.Contains(pi.Name)) {
                    SizeF textSize = Graphics.FromHwndInternal(IntPtr.Zero)
                        .MeasureString(descriptionAttribute.Description, this.ColumnHeadersDefaultCellStyle.Font);
                    if (this.Columns[pi.Name].Width < textSize.Width + adjustWith) {
                        this.Columns[pi.Name].Width = (int)(textSize.Width) + adjustWith;
                    }
                    this.Columns[pi.Name].HeaderText = descriptionAttribute.Description;
                    if (pi.PropertyType == typeof(decimal) ||
                        pi.PropertyType == typeof(float) ||
                        pi.PropertyType == typeof(double) ||
                        pi.PropertyType == typeof(Single) ||
                        pi.PropertyType == typeof(decimal?) ||
                        pi.PropertyType == typeof(float?) ||
                        pi.PropertyType == typeof(double?) ||
                        pi.PropertyType == typeof(Single?)) {
                        this.Columns[pi.Name].DefaultCellStyle = new DataGridViewCellStyle() {
                            Format = "G0",
                            NullValue = null
                        };
                    }
                }
            }
            if (this.IsShowCheckboxForSelected) {
                if (!this.Columns.Contains("chkKey")) {
                    this.ReadOnly = false;
                    foreach (DataGridViewColumn column in this.Columns) { column.ReadOnly = true; }
                    DataGridViewCheckBoxColumnCanSelectAllEx checkColumn = new DataGridViewCheckBoxColumnCanSelectAllEx();
                    checkColumn.Name = "chkKey";
                    checkColumn.HeaderText = string.Empty;
                    checkColumn.Width = 30;
                    this.Columns.Insert(0, checkColumn);
                }
            }

            if (this.IsClearSelectionWhenLeaveEx) {
                this.ClearSelection();
            }

            foreach (DataGridViewRow row in this.Rows) {
                foreach (DataGridViewColumn column in this.Columns) {
                    if (Convert.ToString(this[column.Name, row.Index].FormattedValue) == "已审核") {
                        row.Cells[0].Style = new DataGridViewCellStyle() { BackColor = Color.Red };
                        break;
                    }
                }
            }
        }

        protected override void OnEnter(EventArgs e) {
            base.OnEnter(e);
            if (this.EnterEx != null && this.Rows.Count > 0) {
                this.Focus();
                this.CurrentCell = this.Rows[this.EnterEx.RowIndex].Cells[this.EnterEx.ColumnIndex];
                if (this.EnterEx.IsBeginEdit) {
                    this.BeginEdit(this.EnterEx.IsBeginEditSelectedText);
                }
            }
        }

        protected override void OnLeave(EventArgs e) {
            base.OnLeave(e);
            if (this.IsClearSelectionWhenLeaveEx) {
                this.ClearSelection();
            }
        }

        protected override void OnRowPostPaint(DataGridViewRowPostPaintEventArgs e) {
            base.OnRowPostPaint(e);
            if (this.IsShowRowHeaderNumberEx) {
                Font font = this.ColumnHeadersDefaultCellStyle.Font;
                string number = (e.RowIndex + 1).ToString();
                int stringWith = (int)(e.Graphics.MeasureString(number, font).Width);
                int singleWith = (int)(e.Graphics.MeasureString("0", font).Width);

                int rowHeaderWithNew = this.RowHeadersWidth < stringWith + 3 * singleWith
                    ? stringWith + 3 * singleWith : this.RowHeadersWidth;
                Rectangle bounds = new Rectangle(e.RowBounds.Left + singleWith, e.RowBounds.Top,
                    rowHeaderWithNew - 2 * singleWith, e.RowBounds.Height);
                StringFormat position = new StringFormat() {
                    Alignment = StringAlignment.Far,
                    LineAlignment = StringAlignment.Center
                };
                e.Graphics.DrawString(number, font, SystemBrushes.ControlText, bounds, position);
                this.RowHeadersWidth = rowHeaderWithNew;
            }
        }


        private string BindProperty(object property, string propertyName) {
            string retValue = "";

            if (propertyName.Contains(".")) {
                PropertyInfo[] arrayProperties;
                string leftPropertyName;

                leftPropertyName = propertyName.Substring(0, propertyName.IndexOf("."));
                arrayProperties = property.GetType().GetProperties();

                foreach (PropertyInfo propertyInfo in arrayProperties) {
                    if (propertyInfo.Name == leftPropertyName) {
                        retValue = BindProperty(
                          propertyInfo.GetValue(property, null),
                          propertyName.Substring(propertyName.IndexOf(".") + 1));
                        break;
                    }
                }
            }
            else {
                object objVal;
                Type propertyType;
                PropertyInfo propertyInfo;

                propertyType = property.GetType();
                propertyInfo = propertyType.GetProperty(propertyName);
                objVal = propertyInfo.GetValue(property, null);
                retValue = objVal == null ? string.Empty : objVal.ToString();
            }

            return retValue;
        }
    }
}
